#ifndef CCR_H
#define CCR_H
#include <grape/grape.h>
#include <fstream>
#include <memory>
#include "ccr/ccr_context.h"
namespace grape {
template <typename FRAG_T>
class CCR : public ParallelAppBase<FRAG_T, CCRContext<FRAG_T>>,
            public ParallelEngine {
 public:
  INSTALL_PARALLEL_WORKER(CCR<FRAG_T>, CCRContext<FRAG_T>, FRAG_T)
  using vertex_t = typename fragment_t::vertex_t;

  void PEval(const fragment_t& frag, context_t& ctx,
             message_manager_t& messages) {
    std::cout << "process PEval function\n";
    ReadFile(frag.fid(), frag.fnum(), ctx);
    messages.ForceContinue();
  }
  void IncEval(const fragment_t& frag, context_t& ctx,
               message_manager_t& messages) {
    std::cout << "process IncEval\n";
  }

 private:
  void ReadFile(fid_t fid, fid_t fnum, context_t& ctx) {
    if (ctx.curent_graph_) {
      std::cout << "ptr is not empty!\n";
      exit(-1);
    }
    auto vertex_file_path = ctx.vertex_file_path_;
    auto edge_file_path = ctx.edge_file_path_;
    // load graph
    std::ifstream ifs(vertex_file_path);
    if (not ifs.is_open()) {
      std::cerr << "can not open file: " << vertex_file_path << "\n";
      exit(0);
    }

    // verter 格式，第一行为节点总数，第i+1行为第i个节点的node、start、end
    uint32_t vnum;
    ifs >> vnum;
    uint32_t batch = vnum / fnum;
    // ptr = std::make_unique<Graph>();
    ctx.curent_graph_.reset(new Graph());
    if (!ctx.curent_graph_) {
      std::cout << "assign failed\n";
      exit(-1);
    }

    uint32_t node, start, end, line = 0;
    while (ifs >> node >> start >> end) {
      // TODO: add partition
      if (fid == line / batch) {
        int idx = ctx.curent_graph_->num_vertices();
        ctx.global2local_.insert(std::make_pair(line, idx));
        ctx.curent_graph_->addVertex(node, start, end);
      }
      line++;
    }
    ifs.close();

    ifs.open(edge_file_path);
    if (not ifs.is_open()) {
      std::cerr << "can not open file: " << vertex_file_path << "\n";
      exit(0);
    }
    uint32_t a, b;
    while (ifs >> a >> b) {
      // 如果两个节点都在该分区内,直接add即可
      if (a / batch == fid and b / batch == fid) {
        ctx.curent_graph_->addEdge(ctx.global2local_[a], ctx.global2local_[b]);
      } else if (a / batch == fid and b / batch != fid) {
        // 出边不在分区内
        // if (ctx.outedge_.find(a) == ctx.outedge_.end()) {
        //   ctx.outedge_.insert(std::make_pair(a, std::vector<uint32_t>()));
        // }
        ctx.outedge_[a].push_back(b);
      } else if (a / batch != fid and b / batch == fid) {
        // 入边不在分区内

        // if (ctx.inedge_.find(a) == ctx.inedge_.end()) {
        //   ctx.inedge_.insert(std::make_pair(a, std::vector<uint32_t>()));
        // }
        ctx.inedge_[a].push_back(b);
      }
    }
  }
};
}  // namespace grape

#endif